#ifndef GPU_PRIMITIVES_H
#define GPU_PRIMITIVES_H
#include "stdafx.h"
#include "Basic/StringBuilder.h"
#include "DeviceList.h"
#include "BatchedKernelFunctor.h"

namespace RayTracePro
{
	using namespace GxLibBasic;
	typedef unsigned int uint;

	class GpuScan
	{
	private:
		cl::Kernel ckScanExclusiveLocal1, ckScanExclusiveLocal2, ckUniformUpdate, ckFinalUpdate;
		cl_mem d_Buffer, d_Buffer2;
	private:
		void scanExclusiveLocal2(cl_command_queue cqCommandQueue, cl_mem d_Buffer, cl_mem d_Dst, cl_mem d_Src, uint n, uint size, uint stepSize);
		size_t scanExclusiveLocal1(cl_command_queue cqCommandQueue, cl_mem d_Dst, cl_mem d_Src, uint n, uint size);
		size_t scanExclusiveShort(cl_command_queue cqCommandQueue, cl_mem d_Dst, cl_mem d_Src, uint batchSize, uint arrayLength);
		size_t uniformUpdate(cl_command_queue cqCommandQueue, cl_mem d_Dst, cl_mem d_Buffer, uint n);
		size_t scanExclusiveLarge(cl_command_queue cqCommandQueue, cl_mem d_Dst, cl_mem d_Src, uint batchSize, uint arrayLength);
		void finalUpdate(cl_command_queue cqCommandQueue, cl_mem d_Dst, cl_mem d_Buffer, uint n, uint stepSize);
	public:
		GpuScan(cl_context cxGPUContext, cl_command_queue cqParamCommandQue);
		~GpuScan();
		int GetScanArrayAllocationSize(int size);
		void Scan(cl_mem bufferOut, cl_mem bufferIn, int size);
	};

	class GpuSort_Int4
	{
	private:
		static const int _valueSize = 12;
		static const int _keySize = 4;
		static const int _workgroupSize = 32;
		static cl::Kernel _kernel_RadixLocalSort;
		static cl::Kernel _kernel_LocalHistogram;
		static cl::Kernel _kernel_RadixPermute;	
		cl::Buffer _clBuffer_radixHist1, _clBuffer_radixHist2;
		int _datasetSize;
		void radixLocal(const size_t* global, const size_t* local, cl_mem data, cl_mem hist, cl_mem blockHists, int bitOffset);
		void localHistogram(const size_t* global, const size_t* local, cl_mem data, cl_mem hist, cl_mem blockHists, int bitOffset);
		void radixPermute(const size_t* global, const size_t* local, cl_mem dataIn, cl_mem dataOut, cl_mem histScan, cl_mem blockHists, int bitOffset, unsigned int numBlocks);
	public:
		static void GetSource(StringBuilder & sb);
		static void Init();
		GpuSort_Int4()
		{
			_datasetSize = 0;
		}
		void Sort(const cl::Buffer & bufferIn, const cl::Buffer & bufferOut, int size);
	};
}

#endif